package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xuecheng.commons.constants.CommonConstants;
import com.xuecheng.commons.constants.CourseConstants;
import com.xuecheng.commons.enums.ErrorCode;
import com.xuecheng.commons.model.dto.CourseAuditDto;
import com.xuecheng.commons.model.dto.CourseBaseDto;
import com.xuecheng.commons.model.dto.CourseDto;
import com.xuecheng.commons.model.dto.PageRequest;
import com.xuecheng.commons.model.vo.CourseBaseVo;
import com.xuecheng.commons.model.vo.PageResponseResult;
import com.xuecheng.commons.model.vo.ResponseResult;
import com.xuecheng.commons.utils.AuthInfoHolder;
import com.xuecheng.commons.utils.BeanHelper;
import com.xuecheng.content.config.MinioProperties;
import com.xuecheng.content.domain.CourseBase;
import com.xuecheng.content.domain.CoursePub;
import com.xuecheng.content.domain.Teachplan;
import com.xuecheng.content.mappers.CourseBaseMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.content.service.CoursePubService;
import com.xuecheng.content.service.TeachplanService;
import com.xuecheng.web.exceptions.BusinessException;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.errors.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author itheima
 * @since 2022-09-17
 */
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {


    @Override
    public PageResponseResult<CourseBase> findAll(CourseDto dto, PageRequest pageRequest) {
        //1.设置分页条件
        Page<CourseBase> page = new Page<>(pageRequest.getPageNo(), pageRequest.getPageSize());
        //2.设置查询条件
        LambdaQueryWrapper<CourseBase> wrapper = new LambdaQueryWrapper<>();
        //wrapper.eq(CourseBase::getCompanyId, AuthInfoHolder.getCompanyId());
        wrapper.eq(StringUtils.isNotEmpty(dto.getAuditStatus()),CourseBase::getAuditStatus,dto.getAuditStatus());
        wrapper.like(StringUtils.isNotEmpty(dto.getCourseName()),CourseBase::getName,dto.getCourseName());
        wrapper.like(StringUtils.isNotEmpty(dto.getTeachmode()),CourseBase::getTeachmode,dto.getTeachmode());
        //3.查询
        Page<CourseBase> pageList = this.page(page, wrapper);

        return new PageResponseResult(pageList.getTotal(),pageList.getRecords());
    }

    @Autowired
    private MinioProperties prop;
    @Autowired
    private MinioClient client;
    //上传课程封面图片
    @Override
    public ResponseResult<String> upload(MultipartFile uploadFile) throws Exception {
        //1.获取输入流
        InputStream inputStream = uploadFile.getInputStream();
        //2.设置文件上传的位置
        String filePath="/images/"+new SimpleDateFormat("yyyy/MM/dd/")
                        .format(new Date())+ UUID.randomUUID().toString()+
                        uploadFile.getOriginalFilename();
        //3.设置文件上传对象并上传
        PutObjectArgs objectArgs = PutObjectArgs.builder()
                .contentType("image/jpg") //文件类型
                .stream(inputStream,inputStream.available(),-1) //文件输入流
                .bucket(prop.getBucket()) //文件的存储空间
                .object(filePath)
                .build();
        client.putObject(objectArgs);
        //4.构造访问路径
        String url=prop.getDomain()+"/"+prop.getBucket()+filePath;
        return ResponseResult.okResult(url);
    }
    @Autowired
    private TeachplanService teachplanService;
    //保存课程
    @Override
    public ResponseResult<CourseBaseVo> saveCourseBase(CourseBaseDto dto) {
        //0.验证dto参数
        //1.构造保存对象courseBase
        CourseBase courseBase = BeanHelper.copyProperties(dto, CourseBase.class);
        //2.手动补充缺失的数据
        //courseBase.setCompanyId(AuthInfoHolder.getCompanyId());
        courseBase.setCompanyName(AuthInfoHolder.getAuthInfo().getCompanyName());
        courseBase.setAuditStatus(CourseConstants.AUDIT_UNPAST_STATUS);//审核状态：未提交
        courseBase.setStatus(CommonConstants.USING_FLAG);//课程状态：使用中
        courseBase.setCreateDate(new Date());//创建时间
        //3.设置章节数（需要后续改造）
        courseBase.setPlanNum(3);
        //4.保存到数据库
        boolean save = this.save(courseBase);
        //失败时返回错误信息
        if (!save) {
            throw new BusinessException(ErrorCode.ADDEERROR);
        }
        //补充：保存课程时也要保存一级课程大纲
        Teachplan tp = new Teachplan();
        tp.setPname(courseBase.getName());
        tp.setParentid(0L);
        tp.setGrade(1);
        tp.setCourseId(courseBase.getId());
        tp.setStatus(1);
        tp.setCompanyId(AuthInfoHolder.getCompanyId());
        tp.setCreateDate(new Date());
        teachplanService.save(tp);
        //4.构造返回对象
        CourseBaseVo courseBaseVo = new CourseBaseVo();
        courseBaseVo.setCourseBaseId(courseBase.getId());
        //5.返回
        return ResponseResult.okResult(courseBaseVo);
    }

    //根据课程id删除课程
    @Override
    public ResponseResult deleteByCourseId(Long courseId) {
        //1.根据courseId查询课程，获取审核状态
        CourseBase courseBase = this.getById(courseId);
        if (courseBase == null) {
            throw  new BusinessException(ErrorCode.NOTFOUND);
        }
        String auditStatus = courseBase.getAuditStatus();
        //2.对于审核状态为：已提交，已发布，已审核的课程。抛出自定义业务异常
        if (auditStatus.equals(CourseConstants.AUDIT_COMMIT_STATUS) ||
                auditStatus.equals(CourseConstants.AUDIT_PASTED_STATUS) ||
                auditStatus.equals(CourseConstants.AUDIT_PUBLISHED_STATUS)) {
            throw new BusinessException(ErrorCode.DELETEERROR);
        }
        //3.对课程进行逻辑删除
        courseBase.setStatus(0);
        boolean remove = this.removeById(courseId);
        //4.返回结果
        if (!remove) {
            throw new BusinessException(ErrorCode.ADDEERROR);
        }
        return ResponseResult.okResult();
    }
    //修改课程
    @Override
    public ResponseResult<CourseBaseVo> updateCourseBase(CourseBaseDto dto) {
        //0.验证数据格式
        //1.根据课程id查询数据
        CourseBase courseBase = this.getById(dto.getId());
        if (courseBase == null) {
            throw new BusinessException(ErrorCode.DATAERROR);
        }
        //2.判断课程状态是否可修改
        String auditStatus = courseBase.getAuditStatus();
        if (!auditStatus.equals(CourseConstants.AUDIT_DISPAST_STATUS) &&
                !auditStatus.equals(CourseConstants.AUDIT_UNPAST_STATUS)) {
            throw new BusinessException(ErrorCode.UPDATEEERROR);
        }
        //3.设置修改
        CourseBase courseBase1 = BeanHelper.copyProperties(dto, CourseBase.class);
        boolean update = this.updateById(courseBase1);
        if (!update) {
            throw new BusinessException(ErrorCode.ADDEERROR);
        }
        //4.返回
        CourseBaseVo courseBaseVo = new CourseBaseVo();
        courseBaseVo.setCourseBaseId(dto.getId());
        return ResponseResult.okResult(courseBaseVo);
    }
    //机构提交课程
    @Override
    public ResponseResult commit(Long courseBaseId) {
        //1.根据id查询课程状态
        CourseBase courseBase = this.getById(courseBaseId);
        String auditStatus = courseBase.getAuditStatus();
        //2.判断状态是否可以提交
        if (!auditStatus.equals(CourseConstants.AUDIT_UNPAST_STATUS) &&
                !auditStatus.equals(CourseConstants.AUDIT_DISPAST_STATUS)) {
            throw  new BusinessException(ErrorCode.ERROR);
        }
        //3.更改课程状态为已提交
        courseBase.setAuditStatus(CourseConstants.AUDIT_COMMIT_STATUS);
        boolean update = this.updateById(courseBase);
        if (!update) {
            throw new BusinessException(ErrorCode.ERROR);
        }
        return ResponseResult.okResult();
    }
    //管理员审核课程
    @Override
    public ResponseResult approve(CourseAuditDto dto) {
        //1.根据id查询课程状态
        CourseBase courseBase = this.getById(dto.getCourseBaseId());
        String auditStatus = courseBase.getAuditStatus();
        //2.判断状态是否已提交
        if (!auditStatus.equals(CourseConstants.AUDIT_COMMIT_STATUS)) {
            throw  new BusinessException(ErrorCode.ERROR);
        }
        //3.更改课程状态
        courseBase.setAuditStatus(dto.getAuditStatus());
        courseBase.setAuditMind(dto.getAuditMind());
        boolean update = this.updateById(courseBase);
        if (!update) {
            throw new BusinessException(ErrorCode.ERROR);
        }
        return ResponseResult.okResult();
    }
    @Autowired
    private CoursePubService coursePubService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    //根据课程id下架已发布课程
    @Override
    public ResponseResult offline(Long courseId) throws Exception{
        //0.判断课程是否为已发布状态
        CourseBase courseBase = getById(courseId);
        if (courseBase == null || !CourseConstants.AUDIT_PUBLISHED_STATUS.equals(courseBase.getAuditStatus())) {
            throw new BusinessException(ErrorCode.DELETEERROR);
        }
        //1.修改课程审核状态为未提交
        //1-1.课程表
        courseBase.setAuditStatus(CourseConstants.AUDIT_UNPAST_STATUS);
        updateById(courseBase);
        //1-2.课程发布表
        LambdaQueryWrapper<CoursePub> wq = new LambdaQueryWrapper<>();
        wq.eq(CoursePub::getCourseId,courseId);
        CoursePub coursePub = coursePubService.getOne(wq);
        coursePub.setIsPub(0);
        coursePubService.updateById(coursePub);
        //2.根据courseId删除数据库中的课程数据
        removeById(courseId);
        coursePubService.removeById(coursePub);
        //3.删除MinIo中的文件
        //3-1.获取coursePubId
        Long coursePubId = coursePub.getId();
        //3-2.设置文件上传的位置及名字
        String path="/pages/"+coursePubId+".html";
        client.removeObject(RemoveObjectArgs.builder()
                .object(path)
                .bucket(prop.getBucket())
                .build());
        //4.发送MQ消息
        rabbitTemplate.convertAndSend(
                "content-exchange",
                "course.offline",
                coursePubId);//交换机，路由key，消息内容
        return null;
    }
}
